import { ALL, Body, Get, Inject, Post, Query } from '@midwayjs/core';
import {
  CoolController,
  BaseController,
  CoolTag,
  TagTypes,
} from '@cool-midway/core';
import { OrderOrderEntity } from '../../entity/order';
import { OrderOrderService } from '../../service/order';
import { Context } from '@midwayjs/koa';
import moment = require('moment');
import { Between, Repository } from 'typeorm';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { UserInfoService } from '../../../user/service/info';
import { UserInfoEntity } from '../../../user/entity/info';

/**
 * 订单信息
 */
@CoolController({
  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
  entity: OrderOrderEntity,
  service: OrderOrderService,
  pageQueryOp: {
    where: async ctx => {
      const conditions = [];

      const { createTime, endTime } = ctx.request.body;
      const { deviceBindUserId } = ctx.request.body;

      const userInfoService = await ctx.requestContext.getAsync(
        UserInfoService
      );

      const user = await userInfoService.person(ctx.user.id);

      console.log('用户信息', user);


      // 1: 代理, 2: 商户, 3: 平台
      // 如果是代理
      if (user && user.role === 1) {
        conditions.push(['a.deviceBindAgentId = :deviceBindAgentId', { deviceBindAgentId: user.id }]);
        if (deviceBindUserId) {
          conditions.push(['a.deviceBindUserId = :deviceBindUserId', { deviceBindUserId }]);
        }
      }
      // 如果是商户
      else if (user && user.role === 2) {
        conditions.push(['a.deviceBindUserId = :deviceBindUserId', { deviceBindUserId: user.id }]);
      }

      if (createTime) {
        conditions.push(['a.createTime >= :startTime', { startTime: createTime }]);
      }

      if (endTime) {
        conditions.push(['a.createTime <= :endTime', { endTime: endTime }]);
      } 

      // 筛选payStatus为1的订单
      conditions.push(['a.payStatus = :payStatus', { payStatus: 1 }]);

      // 状态筛选
 
      // 时间筛选
      // if (createTime && endTime) {
      //   where.createTime = Between(new Date(createTime), new Date(endTime));
      // }
      return conditions;
    },
    keyWordLikeFields: ['a.orderNo', 'a.deviceNo'],
    join: [
      {
        entity: UserInfoEntity,
        alias: 'b',
        condition: 'a.deviceBindUserId = b.id',
      },
    ],
    select: [
      'a.*',
      'b.phone AS deviceBindPhone',
      'b.nickName AS deviceBindNickName',
      'b.avatarUrl AS deviceBindAvatarUrl',
    ],
  },
  listQueryOp: {
    where: async ctx => { },
    join: [
      {
        entity: UserInfoEntity,
        alias: 'b',
        condition: 'a.deviceBindUserId = b.id',
      },
    ],
    select: [
      'a.*',
      'b.phone AS deviceBindPhone',
      'b.nickName AS deviceBindNickName',
      'b.avatarUrl AS deviceBindAvatarUrl',
    ],
  },
})
export class AppOrderOrderController extends BaseController {
  @Inject()
  orderOrderService: OrderOrderService;

  @Inject()
  ctx: Context;

  @InjectEntityModel(OrderOrderEntity)
  orderOrderEntity: Repository<OrderOrderEntity>;

  // 订单统计
  @Post('/statisticsByDate')
  async statisticsByDate(@Body(ALL) params: any) {
    // 验证日期格式
    const isValidDate = (dateStr: string) => {
      return moment(dateStr, 'YYYY-MM-DD').isValid();
    };

    const { startTime, endTime } = params;

    // 检查必填参数
    if (!startTime || !endTime) {
      return this.fail('请提供startDate和endDate参数');
    }

    // 验证日期有效性
    if (!isValidDate(startTime) || !isValidDate(endTime)) {
      return this.fail('日期格式无效，请使用YYYY-MM-DD格式');
    }

    // 处理时间范围
    const dateRange = [
      moment(startTime).startOf('day'), // 开始日期的00:00:00
      moment(endTime).endOf('day'), // 结束日期的23:59:59
    ];

    // 检查时间顺序
    if (dateRange[0].isAfter(dateRange[1])) {
      return this.fail('开始日期不能晚于结束日期');
    }

    // 调用服务层获取统计数据
    const result = await this.orderOrderService.statisticsByDate(
      dateRange[0].format('YYYY-MM-DD HH:mm:ss'),
      dateRange[1].format('YYYY-MM-DD HH:mm:ss')
    );

    return this.ok(result);
  }

  /**
   * 购买游戏币
   * @param packageId 套餐ID
   */
  /* 不需要登录 */
  @CoolTag(TagTypes.IGNORE_TOKEN)
  @Post('/buy')
  async buyGameCoin(
    /* 套餐ID */
    @Body('packageId') packageId?: number,
    /*  */
    @Body('payAmount') payAmount?: number,
    /* 设备号 */
    @Body('deviceNo') deviceNo?: string,
    /* 微信OpenId */
    @Body('openId') openId?: string,
    // 支付方式 1：微信支付 2：支付宝支付
    @Body('payType') payType?: number
  ) {
    const { ctx } = this;
    const userId = ctx?.user?.id || undefined; // 获取当前用户ID
    const order = await this.orderOrderService.buyGameCoin({
      packageId,
      payAmount,
      userId,
      deviceNo,
      openId,
      payType
    });
    return this.ok(order);
  }

  // 支付回调
  /* 不需要登录 */
  @CoolTag(TagTypes.IGNORE_TOKEN)
  @Post('/callback')
  async callback(@Body() body: any) {
    const result = await this.orderOrderService.paySuccess(body);

    if (result === 'ok') {
      return {
        code: 'SUCCESS',
      };
    } else {
      return {
        code: 'FAIL',
      };
    }
  }

  // 手动投币
  @Post('/manualAdd')
  async manualAdd(@Body() params) {
    const _res = await this.orderOrderService.manualAdd(params);

    return this.ok(_res);
  }

  @Post('/manualAddByOrderNo')
  async manualAddByOrderNo(@Body() params) {
    const _res = await this.orderOrderService.manualAddByOrderNo(params);
    return this.ok(_res);
  }

  @Post('/merchantSummary')
  async merchantSummary(@Body(ALL) params: any) {
    const userInfoService = await this.ctx.requestContext.getAsync(UserInfoService);
    const user = await userInfoService.person(this.ctx.user.id);
    if (!user || user.role !== 1) {
      return this.ok([]);
    }
    const { createTime, endTime } = params || {};
    const qb = this.orderOrderEntity.createQueryBuilder('a')
      .leftJoin(UserInfoEntity, 'b', 'a.deviceBindUserId = b.id')
      .select([
        'a.deviceBindUserId AS userId',
        'b.nickName AS nickName',
        'b.phone AS phone',
        'b.avatarUrl AS avatarUrl',
        'SUM(a.payAmount) AS totalAmount',
        'COUNT(*) AS total',
      ])
      .where('a.deviceBindAgentId = :agentId', { agentId: user.id })
      .andWhere('a.payStatus = :payStatus', { payStatus: 1 });
    if (createTime) {
      qb.andWhere('a.createTime >= :startTime', { startTime: createTime });
    }
    if (endTime) {
      qb.andWhere('a.createTime <= :endTime', { endTime });
    }
    qb.groupBy('a.deviceBindUserId');
    const paidRows = await qb.getRawMany();

    const qbRefund = this.orderOrderEntity.createQueryBuilder('a')
      .leftJoin(UserInfoEntity, 'b', 'a.deviceBindUserId = b.id')
      .select([
        'a.deviceBindUserId AS userId',
        'b.nickName AS nickName',
        'b.phone AS phone',
        'b.avatarUrl AS avatarUrl',
        'COUNT(*) AS refundCount',
        'SUM(a.refundAmount) AS refundAmount',
      ])
      .where('a.deviceBindAgentId = :agentId', { agentId: user.id })
      .andWhere('a.payStatus = :refundStatus', { refundStatus: 3 });
    if (createTime) {
      qbRefund.andWhere('a.refundTime >= :refundStartTime', { refundStartTime: createTime });
    }
    if (endTime) {
      qbRefund.andWhere('a.refundTime <= :refundEndTime', { refundEndTime: endTime });
    }
    qbRefund.groupBy('a.deviceBindUserId');
    const refundRows = await qbRefund.getRawMany();

    const map = new Map<number, any>();
    for (const r of paidRows) {
      const userId = Number(r.userId);
      map.set(userId, {
        userId,
        nickName: r.nickName,
        phone: r.phone,
        avatarUrl: r.avatarUrl,
        totalAmount: Number(r.totalAmount || 0),
        total: Number(r.total || 0),
        refundCount: 0,
        refundAmount: 0,
      });
    }
    for (const r of refundRows) {
      const userId = Number(r.userId);
      const cur = map.get(userId) || {
        userId,
        nickName: r.nickName,
        phone: r.phone,
        avatarUrl: r.avatarUrl,
        totalAmount: 0,
        total: 0,
        refundCount: 0,
        refundAmount: 0,
      };
      cur.refundCount = Number(r.refundCount || 0);
      cur.refundAmount = Number(r.refundAmount || 0);
      map.set(userId, cur);
    }
    return this.ok(Array.from(map.values()));
  }

  @Post('/pageSummary')
  async pageSummary(@Body(ALL) params: any) {
    const page = Number(params?.page || 1);
    const size = Number(params?.size || 20);
    const { createTime, endTime, deviceBindUserId, keyWord } = params || {};

    const userInfoService = await this.ctx.requestContext.getAsync(UserInfoService);
    const user = await userInfoService.person(this.ctx.user.id);

    const base = this.orderOrderEntity.createQueryBuilder('a')
      .leftJoin(UserInfoEntity, 'b', 'a.deviceBindUserId = b.id');

    if (user && user.role === 1) {
      base.andWhere('a.deviceBindAgentId = :agentId', { agentId: user.id });
      if (deviceBindUserId) {
        base.andWhere('a.deviceBindUserId = :deviceBindUserId', { deviceBindUserId });
      }
    } else if (user && user.role === 2) {
      base.andWhere('a.deviceBindUserId = :uid', { uid: user.id });
    }

    const hasStart = !!createTime;
    const hasEnd = !!endTime;
    if (keyWord) {
      base.andWhere('(a.orderNo LIKE :kw OR a.deviceNo LIKE :kw)', { kw: `%${keyWord}%` });
    }

    const qbList = base.clone()
      .andWhere(
        hasStart || hasEnd
          ? `((a.payStatus = :p1${hasStart ? ' AND a.createTime >= :startTime' : ''}${hasEnd ? ' AND a.createTime <= :endTime' : ''}) OR (a.payStatus = :p3${hasStart ? ' AND a.refundTime >= :refundStartTime' : ''}${hasEnd ? ' AND a.refundTime <= :refundEndTime' : ''}))`
          : '(a.payStatus IN (:...statuses))',
        hasStart || hasEnd
          ? { p1: 1, p3: 3, startTime: createTime, endTime, refundStartTime: createTime, refundEndTime: endTime }
          : { statuses: [1, 3] }
      )
      .select([
        'a.*',
        'b.phone AS deviceBindPhone',
        'b.nickName AS deviceBindNickName',
        'b.avatarUrl AS deviceBindAvatarUrl',
      ])
      .orderBy('a.createTime', 'DESC')
      .offset((page - 1) * size)
      .limit(size);

    const list = await qbList.getRawMany();
    const total = await base.clone()
      .andWhere(
        hasStart || hasEnd
          ? `((a.payStatus = :p1${hasStart ? ' AND a.createTime >= :startTime' : ''}${hasEnd ? ' AND a.createTime <= :endTime' : ''}) OR (a.payStatus = :p3${hasStart ? ' AND a.refundTime >= :refundStartTime' : ''}${hasEnd ? ' AND a.refundTime <= :refundEndTime' : ''}))`
          : '(a.payStatus IN (:...statuses))',
        hasStart || hasEnd
          ? { p1: 1, p3: 3, startTime: createTime, endTime, refundStartTime: createTime, refundEndTime: endTime }
          : { statuses: [1, 3] }
      )
      .getCount();

    const paidBase = base.clone().andWhere('a.payStatus = :payStatus', { payStatus: 1 });
    if (createTime) {
      paidBase.andWhere('a.createTime >= :startTime', { startTime: createTime });
    }
    if (endTime) {
      paidBase.andWhere('a.createTime <= :endTime', { endTime });
    }
    const paidRow = await paidBase
      .select('COUNT(*)', 'orderCount')
      .addSelect('SUM(a.payAmount)', 'orderTotalAmount')
      .getRawOne();

    const refundBase = this.orderOrderEntity.createQueryBuilder('a');
    if (user && user.role === 1) {
      refundBase.andWhere('a.deviceBindAgentId = :agentId', { agentId: user.id });
      if (deviceBindUserId) {
        refundBase.andWhere('a.deviceBindUserId = :deviceBindUserId', { deviceBindUserId });
      }
    } else if (user && user.role === 2) {
      refundBase.andWhere('a.deviceBindUserId = :uid', { uid: user.id });
    }
    if (createTime) {
      refundBase.andWhere('a.refundTime >= :refundStartTime', { refundStartTime: createTime });
    }
    if (endTime) {
      refundBase.andWhere('a.refundTime <= :refundEndTime', { refundEndTime: endTime });
    }
    if (keyWord) {
      refundBase.andWhere('(a.orderNo LIKE :kw OR a.deviceNo LIKE :kw)', { kw: `%${keyWord}%` });
    }
    const refundRow = await refundBase
      .andWhere('a.payStatus = :refundStatus', { refundStatus: 3 })
      .select('COUNT(*)', 'refundCount')
      .addSelect('SUM(a.refundAmount)', 'refundTotalAmount')
      .getRawOne();

    return this.ok({
      list,
      pagination: { page, size, total },
      summary: {
        orderCount: Number(paidRow?.orderCount || 0),
        orderTotalAmount: Number(paidRow?.orderTotalAmount || 0),
        refundCount: Number(refundRow?.refundCount || 0),
        refundTotalAmount: Number(refundRow?.refundTotalAmount || 0),
      }
    });
  }
}
